home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ptv1n4.arc / TRANSFER.ASM < prev    next >
Assembly Source File  |  1990-09-13  |  17KB  |  455 lines

  1. %TITLE "transfer.asm"
  2.  
  3. ;**  Resident data-transfer utility. (c) 1990 by Tom Swan.
  4.  
  5.         IDEAL
  6.         JUMPS
  7.  
  8. ;---------------------------------------------------------------
  9. ;                ---- Equates ----
  10. ;---------------------------------------------------------------
  11.  
  12. CR              equ     13      ; ASCII carriage return
  13. LF              equ     10      ; ASCII line feed
  14. TSRINT          equ     64h     ; TSR's interrupt number
  15. STACK_SIZE      equ     2048    ; TSR loader's stack size
  16. BUF_SIZE        equ     512     ; Size of storage buffer
  17.  
  18. ;----- Function numbers
  19.  
  20. FN_GETBLOCK     equ     1       ; Get stored data from TSR
  21. FN_PUTBLOCK     equ     2       ; Save data in TSR
  22. FN_CLEARBLOCK   equ     3       ; Clear data stored in TSR
  23. FN_STATUS       equ     4       ; Retrieve TSR's status
  24.  
  25. ;----- Error codes
  26.  
  27. ERR_BADFUNCTION equ     1       ; Bad function number in AH
  28.  
  29. ;----- Equates for "stuffing" register values on the stack
  30.  
  31. SETCX    equ    [word bp - 6]   ; Location of pushed CX
  32. SETDX    equ    [word bp - 8]   ; Location of pushed DX
  33. SETDS    equ    [word bp - 14]  ; Location of pushed DS
  34. SETFLAGS equ    [word bp + 6]   ; Location of pushed flags
  35. SETCF    equ    01h             ; Value to set pushed cf flag
  36. RESETCF  equ    not SETCF       ; Value to reset pushed cf flag
  37. SETZF    equ    40h             ; Value to set pushed zf flag
  38. RESETZF  equ    not SETZF       ; Value to reset pushed zf flag
  39.  
  40. ;---------------------------------------------------------------
  41. ;                ---- Resident Portion ----
  42. ;---------------------------------------------------------------
  43.  
  44. ;----- The TSR's code segment
  45.  
  46. SEGMENT TSR_code 'TSRCODE'
  47.  
  48. ;---------------------------------------------------------------
  49. ; TSR_isr       The TSR's Interrupt Service Routine (ISR)
  50. ;---------------------------------------------------------------
  51. ; Input:
  52. ;       ah = function code (1, 2, 3, or 4)
  53. ;       Note: See individual functions for register requirements
  54. ;       Note: Uses 00 bytes of caller's stack
  55. ; Output:
  56. ;       cf = 0 (no error)
  57. ;       cf = 1 (error: use function 4 to determine cause)
  58. ;       zf = 0 (not in progress)
  59. ;       zf = 1 (in progress--retry)
  60. ;       Note: cf and zf are meaningless for function 4
  61. ; Registers:
  62. ;       cf, zf, cx, dx (see individual functions for details)
  63. ;---------------------------------------------------------------
  64. PROC    TSR_isr         far
  65.  
  66.         ASSUME  cs:TSR_code, ds:TSR_data
  67.  
  68.         sti                     ; Enable interrupts
  69.         push    bp              ; Prepare bp for addressing stack
  70.         mov     bp, sp
  71.         push    ax bx cx dx si di ds es ; Save other registers
  72.         mov     bx, TSR_data            ; Prepare ds for 
  73.         mov     ds, bx                  ;  addressing TSR's data seg
  74.  
  75. ;----- Execute reentrant routines (may be called recursively)
  76.  
  77.         cmp     ah, FN_STATUS           ; Do Status function
  78.         je      Status
  79.  
  80. ;----- Check if TSR is already running
  81.  
  82.         and     SETFLAGS, RESETZF       ; Reset pushed zf to 0
  83.         cmp     [inProgress], 0         ; Check inProgress flag
  84.         je      TSR_inactive            ; Continue if flag = 0
  85.         or      SETFLAGS, SETZF         ; Set pushed zf to 1
  86.         jmp     TSR_quit2               ; Quit TSR without resetting
  87.                                         ;  the in-progress flag
  88.  
  89. ;----- Execute non-reentrant routines. The next instruction should
  90. ;      be the first to write to the TSR's data segment.
  91.  
  92. TSR_inactive:
  93.         inc     [inProgress]            ; Set TSR inProgress flag
  94.         cmp     ah, FN_GETBLOCK         ; Do GetBlock function
  95.         je      GetBlock
  96.         cmp     ah, FN_PUTBLOCK         ; Do PutBlock function
  97.         je      PutBlock
  98.         cmp     ah, FN_CLEARBLOCK       ; Do ClearBlock function
  99.         je      ClearBlock
  100.         mov     al, ERR_BADFUNCTION     ; Report bad function number
  101.  
  102. ;----- All errors except in progress exit from here
  103.  
  104. TSR_errExit:
  105.         mov     [errorCode], al         ; Save error code
  106.         or      SETFLAGS, SETCF         ; Set pushed cf bit to 1
  107.         jmp     short TSR_quit          ; Jump to skip next section
  108.  
  109. ;----- All nonerrors except status request exit from here
  110.  
  111. TSR_exit:
  112.         mov     [errorCode], 0          ; Reset error code
  113.         and     SETFLAGS, RESETCF       ; Reset pushed cf bit to 0
  114. TSR_quit:
  115.         mov     [inProgress], 0         ; Reset inProgress flag
  116.  
  117. ;----- Status request and in-progress error exit from here
  118.  
  119. TSR_quit2:
  120.         pop     es ds di si dx cx bx ax bp
  121.         iret
  122.  
  123. ENDP    TSR_isr
  124.  
  125. ;---------------------------------------------------------------
  126. ; GetBlock              Get stored data from TSR
  127. ;---------------------------------------------------------------
  128. ; Input:
  129. ;       ah = 1 (FN_GETBLOCK)
  130. ;       cx = size of destination block
  131. ;       es:di = destination address
  132. ;       Note: Destination must be large enough to hold at
  133. ;             least cx bytes. In no case will more than cx
  134. ;             bytes be transferred to the destination.
  135. ;       Note: Contents of stored data are not disturbed.
  136. ; Output:
  137. ;       cf = 0 (no error)
  138. ;       cf = 1 (error: use function 4 to determine cause)
  139. ;       cx = number of bytes actually transferred
  140. ;       Note: If cx = 0, then buffer was empty, and no data
  141. ;             was transferred to the destination.
  142. ; Registers:
  143. ;       cx
  144. ;---------------------------------------------------------------
  145. PROC    GetBlock
  146.  
  147.         mov     ax, [bufcount]          ; Get buffer count
  148.         cmp     cx, ax                  ; Is cx <= bufcount?
  149.         jbe     GetBlock_10             ; Jump if yes
  150.         mov     cx, ax                  ; Else limit cx to bufcount
  151. GetBlock_10:
  152.         mov     ax, cx                  ; Save transfer count
  153.         jcxz    GetBlock_99             ; Exit if cx = 0
  154.         mov     si, offset buffer       ; ds:si = source address
  155.         cld                             ; Move in forward direction
  156.         rep     movsb                   ; Transfer
  157. GetBlock_99:
  158.         mov     SETCX, ax               ; Set cx = bytes transferred
  159.         jmp     TSR_exit                ; Normal exit--no errors
  160.  
  161. ENDP    GetBlock
  162.  
  163. ;---------------------------------------------------------------
  164. ; PutBlock              Save data in TSR
  165. ;---------------------------------------------------------------
  166. ; Input:
  167. ;       ah = 2 (FN_PUTBLOCK)
  168. ;       cx = number of bytes to transfer
  169. ;       dl = data type code (0=untyped)
  170. ;       ds:si = source address
  171. ;       Note: Copies cx bytes from source to internal
  172. ;             buffer. Value in cx must be <= buffer
  173. ;             size. If cx = 0, the buffer is erased.
  174. ; Output:
  175. ;       cf = 0 (no error)
  176. ;       cx = number of bytes actually saved
  177. ; Registers:
  178. ;       cx
  179. ;---------------------------------------------------------------
  180. PROC    PutBlock
  181.  
  182.         mov     [buftype], dl           ; Save data type code
  183.         cmp     cx, BUF_SIZE            ; Is cx <= max buffer size?
  184.         jbe     PutBlock_10             ; If yes, continue
  185.         mov     cx, BUF_SIZE            ; Else limit cx to max
  186. PutBlock_10:
  187.         push    ds                      ; Set es to TSR's
  188.         pop     es                      ;  data segment
  189.         mov     di, offset buffer       ; es:di = destination address
  190.         mov     [bufcount], cx          ; Save buffer count
  191.         mov     SETCX, cx               ; Save count in stack too
  192.         mov     ax, SETDS               ; Get saved DS from stack
  193.         mov     ds, ax                  ; ds:si = source address
  194.         jcxz    PutBlock_99             ; Exit if count = 0
  195.         cld                             ; Move in forward direction
  196.         rep     movsb                   ; Transfer
  197. PutBlock_99:
  198.         push    es              ; Restore TSR's data segment 
  199.         pop     ds              ;  from es to ds
  200.         jmp     TSR_exit        ; Normal exit--no errors
  201.  
  202. ENDP    PutBlock
  203.  
  204. ;---------------------------------------------------------------
  205. ; ClearBlock            Clear data stored in TSR
  206. ;---------------------------------------------------------------
  207. ; Input:
  208. ;       ah = 3 (FN_CLEARBLOCK)
  209. ;       Note: Erases internal buffer.
  210. ; Output:
  211. ;       cf = 0 (no error)
  212. ; Registers:
  213. ;       none
  214. ;---------------------------------------------------------------
  215. PROC    ClearBlock
  216.  
  217.         mov     [bufcount], 0   ; Reset buffer counter
  218.         mov     [buftype], 0    ; Reset buffer data type code
  219.         jmp     TSR_exit        ; Normal exit--no errors
  220.  
  221. ENDP    ClearBlock
  222.  
  223. ;---------------------------------------------------------------
  224. ; Status                Retrieve TSR's status
  225. ;---------------------------------------------------------------
  226. ; Input:
  227. ;       ah = 4 (FN_STATUS)
  228. ;       Note: This routine does not write to the TSR's
  229. ;             data segment; therefore, it may be called
  230. ;             recursively (i.e. this function is reentrant.)
  231. ; Output:
  232. ;       dh = error code from previous operation
  233. ;       dl = data type code
  234. ;       cx = number of bytes stored in buffer
  235. ; Registers:
  236. ;       cx, dx 
  237. ;---------------------------------------------------------------
  238. PROC    Status
  239.  
  240.         mov     ax, [bufcount]  ; Get count of bytes in buffer
  241.         mov     SETCX, ax       ; Stuff into pushed CX on stack
  242.         mov     ax, [errNtype]  ; Get error and type codes
  243.         mov     SETDX, ax       ; Stuff into pushed DX on stack
  244.         jmp     TSR_quit2       ; Alternate exit
  245.  
  246. ENDP    Status
  247.  
  248. ENDS    TSR_code
  249.  
  250. ;----- The TSR's data segment
  251.  
  252. SEGMENT TSR_data 'TSRDATA'
  253.  
  254. DOSversion      dw      0       ; Major and minor version numbers
  255. inProgress      db      0       ; 0=TSR not active; 1=TSR active
  256.                 db      0       ; Keep data word aligned
  257.  
  258. ;----- Note: Order of next two bytes is critical. Don't move!
  259.  
  260. LABEL   errNtype        word
  261. buftype         db      0       ; Buffer data-type code
  262. errorCode       db      0       ; Previous operation's error code
  263.  
  264. bufcount        dw      0       ; Bytes stored in buffer
  265.  
  266. ;----- The storage buffer
  267.  
  268. buffer          db      BUF_SIZE dup(0)
  269.  
  270. ENDS    TSR_data
  271.  
  272. ;---------------------------------------------------------------
  273. ;                ---- Transient Portion ----
  274. ;---------------------------------------------------------------
  275.  
  276. ;----- The TSR loader's code segment
  277.  
  278. SEGMENT LOADER_code 'CODE'
  279.  
  280. PROC    Load_TSR
  281.  
  282.         ASSUME  cs:LOADER_code, ds:TSR_data
  283.  
  284.         mov     ax, TSR_data    ; Initialize ds to address
  285.         mov     ds, ax          ;  the TSR's data segment
  286.  
  287.         ASSUME  ds:TSR_data
  288.  
  289.         call    CheckVersion    ; Abort if DOS version = 1.x
  290.         jnc     LTSR_10         ; Jump if cf = 0 (no error)
  291.         mov     al, 1           ; Select error message #1
  292.         jmp     ErrorExit       ; End program if DOS 1.x
  293. LTSR_10:
  294.         push    es              ; Save PSP address on stack
  295.         push    ds              ; Save TSR data segment
  296.  
  297. ;----- Install interrupt service routine
  298.  
  299.         mov     al, TSRINT      ; Get current vector for
  300.         mov     ah, 35h         ;  the TSR's interrupt number
  301.         int     21h             ;  using DOS function 35h.
  302.         mov     bx, es          ; Copy segment address to bx
  303.         or      bx, bx          ;  and test if bx = 0.
  304.         jz      LTSR_20         ; Jump if vector is not used
  305.         pop     ds              ; Restore TSR data seg to ds
  306.         pop     es              ; Restore PSP address to es
  307.         mov     al, 2           ; Set error code number
  308.         jmp     ErrorExit       ; And exit with error message
  309. LTSR_20:
  310.         mov     ax, TSR_code            ; Set ds to TSR's code 
  311.         mov     ds, ax                  ;  segment.
  312.  
  313.         ASSUME  ds:TSR_code
  314.  
  315.         mov     dx, offset TSR_isr      ; Set dx to TSR's int service
  316.         mov     al, TSRINT              ;  routine, and set the
  317.         mov     ah, 25h                 ;  interrupt vector for TSRINT
  318.         int     21h                     ;  with DOS function 25h.
  319.         pop     ds                      ; Restore TSR data segment
  320.  
  321. ;----- Terminate and stay resident
  322.  
  323.         mov     ax, LOADER_data         ; Initialize ds to loader's
  324.         mov     ds, ax                  ;  data segment
  325.  
  326.         ASSUME  ds:LOADER_data
  327.  
  328.         mov     dx, offset doneMsg ; Display "TSR Loaded" message
  329.         mov     ah, 09h            ;  by calling DOS print-
  330.         int     21h                ;  string function.
  331.         pop     ax                 ; Restore PSP seg addr to ax
  332.         mov     dx, cs             ; dx <- Transient start addr
  333.         sub     dx, ax             ; dx <- Resident size
  334.         mov     ax, 3100h          ; DOS terminate function
  335.         int     21h                ; Terminate, stay resident
  336.                                    ; al = 0 (return code)
  337. ENDP    LOAD_TSR
  338.  
  339. ;---------------------------------------------------------------
  340. ; ErrorExit             Exit with error message and code in al
  341. ;---------------------------------------------------------------
  342. ; Input:
  343. ;       al = error code 1..n
  344. ;       ds = address of TSR's data segment
  345. ;       es = psp segment address (DOS 1.x only)
  346. ; Output:
  347. ;       none. program halted.
  348. ; Registers:
  349. ;       none preserved
  350. ;---------------------------------------------------------------
  351. PROC    ErrorExit       near
  352.  
  353.         ASSUME  ds:TSR_data
  354.  
  355.         push    [DOSversion]            ; Save DOS version on stack
  356.         push    ax                      ; Save error code on stack
  357.         mov     ax, LOADER_data         ; Initialize ds to loader's
  358.         mov     ds, ax                  ;  data segment
  359.  
  360.         ASSUME  ds:LOADER_data
  361.  
  362.         mov     dx, offset errorMsg ; Address "ERROR: " string
  363.         mov     ah, 09h             ; DOS print-string function
  364.         int     21h                 ; Display error lead-in
  365.         pop     ax                  ; Restore error code to al
  366.         push    ax                  ; Save code again
  367.         cmp     al, 1               ; Does error code = 1?
  368.         jne     test2               ; If not, check next code
  369.         mov     dx, offset errmsg1  ; Address error message 1
  370.         jmp     Exit                ; Display message and exit
  371. test2:
  372.         cmp     al, 2               ; Error code 2
  373.         jne     test3
  374.         mov     dx, offset errmsg2
  375.         jmp     Exit
  376.  
  377. ;----- Other error codes or default
  378.  
  379. test3:
  380.         mov     dx, offset defaultmsg ; Default error message
  381.  
  382. ;----- Display message and exit. Error code still in al.
  383.  
  384. Exit:
  385.         mov     ah, 09h             ; DOS print-string function
  386.         int     21h                 ; Display error message
  387.         pop     ax                  ; Restore error code to al
  388.         pop     bx                  ; Restore DOS version to bx
  389.         cmp     bl, 2               ; Is it ver. 2.x or higher?
  390.         jb      ExitDOS1x           ; Jump for versions 1.x
  391.  
  392. ;----- End program for DOS 2.x and higher
  393.  
  394.         mov     ah, 4ch             ; DOS terminate with code
  395.         int     21h                 ; End with error code in al
  396.  
  397. ;----- End program for DOS 1.x
  398.  
  399. ExitDOS1x:
  400.         push    es                  ; Push psp segment onto stack
  401.         xor     ax,ax               ; Set ax to 0000
  402.         push    ax                  ; Push 0000 (stack=es:0000)
  403.         retf                        ; Far return exits program
  404.  
  405. ENDP    ErrorExit
  406.  
  407. ;---------------------------------------------------------------
  408. ; CheckVersion          Test DOS version
  409. ;---------------------------------------------------------------
  410. ; Input:
  411. ;       ds = address of TSR's data segment
  412. ; Output:
  413. ;       DOSversion = version number
  414. ;       ax = version number
  415. ;       cf = 0 = DOS version 2.x or higher
  416. ;       cf = 1 = DOS version 1.x
  417. ; Registers:
  418. ;       ax
  419. ;---------------------------------------------------------------
  420. PROC    CheckVersion    near
  421.  
  422.         ASSUME ds:TSR_data
  423.  
  424.         mov     ah, 30h             ; DOS get-version function
  425.         int     21h                 ; Get DOS version
  426.         mov     [word DOSversion], ax ; Save in TSR data seg
  427.         cmp     al, 02h             ; Test major revision number
  428.         ret                         ;  cf = 0 if al >= 2
  429.                                     ;  cf = 1 if al < 2
  430. ENDP    CheckVersion
  431.  
  432. ENDS    LOADER_code
  433.  
  434. ;----- TSR loader's data segment
  435.  
  436. SEGMENT LOADER_data 'DATA'
  437.  
  438. doneMsg         db      CR,LF,'Data Transfer Utility'
  439.                 db      CR,LF,'(c) 1990 by Tom Swan'
  440.                 db      CR,LF,'TSR Loaded',CR,LF,'$'
  441. errorMsg        db      CR,LF,'ERROR: ', '$'
  442. errmsg1         db      'Requires DOS 2.0 or later',CR,LF,'$'
  443. errmsg2         db      'Interrupt vector in use',CR,LF,'$'
  444. defaultmsg      db      'Unknown cause',CR,LF,'$'
  445.  
  446. ENDS    LOADER_data
  447.  
  448. ;----- The TSR loader's stack segment
  449.  
  450. SEGMENT LOADER_stack stack 'STACK'
  451.         db      STACK_SIZE dup(?)
  452. ENDS    LOADER_stack
  453.  
  454. END     Load_TSR
  455.